﻿using SanJ.FreeCare.Abp.Authorization.Users;
using System;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using Volo.Abp.Uow;

namespace SanJ.FreeCare.Friendships
{
    public class FriendshipManager : DomainService, IFriendshipManager
    {
        private readonly IRepository<Friendship, Guid> _friendshipRepository;
        private readonly IUnitOfWorkManager _unitOfWorkManager;

        public FriendshipManager(
            IRepository<Friendship, Guid> friendshipRepository,
            IUnitOfWorkManager unitOfWorkManager)
        {
            _friendshipRepository = friendshipRepository;
            _unitOfWorkManager = unitOfWorkManager;
        }

        public async Task CreateFriendshipAsync(Friendship friendship)
        {
            if (friendship.TenantId == friendship.FriendTenantId &&
                friendship.UserId == friendship.FriendUserId)
            {
                throw new UserFriendlyException("YouCannotBeFriendWithYourself");
            }

            await _friendshipRepository.InsertAsync(friendship);
        }

        public async Task UpdateFriendshipAsync(Friendship friendship)
        {
            await _friendshipRepository.UpdateAsync(friendship);
        }

        public async Task<Friendship> GetFriendshipOrNullAsync(UserIdentifier user, UserIdentifier probableFriend)
        {
            return await _friendshipRepository.FirstOrDefaultAsync(friendship =>
                friendship.UserId == user.UserId &&
                friendship.TenantId == user.TenantId &&
                friendship.FriendUserId == probableFriend.UserId &&
                friendship.FriendTenantId == probableFriend.TenantId);
        }

        public async Task BanFriendAsync(UserIdentifier userIdentifier, UserIdentifier probableFriend)
        {
            var friendship = (await GetFriendshipOrNullAsync(userIdentifier, probableFriend));
            if (friendship == null)
            {
                throw new Exception("Friendship does not exist between " + userIdentifier + " and " + probableFriend);
            }

            friendship.State = FriendshipState.Blocked;
            await UpdateFriendshipAsync(friendship);
        }

        public async Task RemoveFriendAsync(UserIdentifier userIdentifier, UserIdentifier probableFriend)
        {
            var friendship = (await GetFriendshipOrNullAsync(userIdentifier, probableFriend));
            if (friendship == null)
            {
                throw new Exception("Friendship does not exist between " + userIdentifier + " and " + probableFriend);
            }

            await _friendshipRepository.DeleteAsync(friendship);
        }

        public async Task AcceptFriendshipRequestAsync(UserIdentifier userIdentifier, UserIdentifier probableFriend)
        {
            var friendship = (await GetFriendshipOrNullAsync(userIdentifier, probableFriend));
            if (friendship == null)
            {
                throw new Exception("Friendship does not exist between " + userIdentifier + " and " + probableFriend);
            }

            friendship.State = FriendshipState.Accepted;
            await UpdateFriendshipAsync(friendship);
        }
    }
}
